Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
56.52% covered (warning)
56.52%
13 / 23
CRAP
96.43% covered (success)
96.43%
1160 / 1203
PptCharts
0.00% covered (danger)
0.00%
0 / 1
56.52% covered (warning)
56.52%
13 / 23
212
96.43% covered (success)
96.43%
1160 / 1203
 render
0.00% covered (danger)
0.00%
0 / 1
5.02
90.91% covered (success)
90.91%
10 / 11
 writeChart
0.00% covered (danger)
0.00%
0 / 1
8.23
84.72% covered (warning)
84.72%
61 / 72
 writeSpreadsheet
0.00% covered (danger)
0.00%
0 / 1
7.04
90.32% covered (success)
90.32%
28 / 31
 writeElementWithValAttribute
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
 writeSingleValueOrReference
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
16 / 16
 writeMultipleValuesOrReference
100.00% covered (success)
100.00%
1 / 1
6
100.00% covered (success)
100.00%
26 / 26
 writeTitle
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
48 / 48
 writePlotArea
100.00% covered (success)
100.00%
1 / 1
12
100.00% covered (success)
100.00%
28 / 28
 writeLegend
100.00% covered (success)
100.00%
1 / 1
5
100.00% covered (success)
100.00%
48 / 48
 writeLayout
0.00% covered (danger)
0.00%
0 / 1
5.27
77.78% covered (warning)
77.78%
21 / 27
 writeTypeArea
0.00% covered (danger)
0.00%
0 / 1
9.02
93.48% covered (success)
93.48%
43 / 46
 writeTypeBar
0.00% covered (danger)
0.00%
0 / 1
17.10
93.07% covered (success)
93.07%
94 / 101
 writeTypeBar3D
0.00% covered (danger)
0.00%
0 / 1
15
96.74% covered (success)
96.74%
89 / 92
 writeTypeDoughnut
0.00% covered (danger)
0.00%
0 / 1
20
95.29% covered (success)
95.29%
81 / 85
 writeTypePie
0.00% covered (danger)
0.00%
0 / 1
15.03
94.94% covered (success)
94.94%
75 / 79
 writeTypePie3D
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
76 / 76
 writeTypeLine
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
81 / 81
 writeTypeRadar
100.00% covered (success)
100.00%
1 / 1
13
100.00% covered (success)
100.00%
82 / 82
 writeTypeScatter
100.00% covered (success)
100.00%
1 / 1
16
100.00% covered (success)
100.00%
85 / 85
 writeChartRelationships
100.00% covered (success)
100.00%
1 / 1
2
100.00% covered (success)
100.00%
8 / 8
 writeSeriesMarker
100.00% covered (success)
100.00%
1 / 1
4
100.00% covered (success)
100.00%
19 / 19
 writeAxis
0.00% covered (danger)
0.00%
0 / 1
19
99.25% covered (success)
99.25%
133 / 134
 writeAxisGridlines
100.00% covered (success)
100.00%
1 / 1
1
100.00% covered (success)
100.00%
4 / 4
1<?php
2/**
3 * This file is part of PHPPresentation - A pure PHP library for reading and writing
4 * presentations documents.
5 *
6 * PHPPresentation is free software distributed under the terms of the GNU Lesser
7 * General Public License version 3 as published by the Free Software Foundation.
8 *
9 * For the full copyright and license information, please read the LICENSE
10 * file that was distributed with this source code. For the full list of
11 * contributors, visit https://github.com/PHPOffice/PHPPresentation/contributors.
12 *
13 * @see        https://github.com/PHPOffice/PHPPresentation
14 *
15 * @copyright   2009-2015 PHPPresentation contributors
16 * @license     http://www.gnu.org/licenses/lgpl.txt LGPL version 3
17 */
18
19declare(strict_types=1);
20
21namespace PhpOffice\PhpPresentation\Writer\PowerPoint2007;
22
23use PhpOffice\Common\Adapter\Zip\ZipInterface;
24use PhpOffice\Common\Drawing as CommonDrawing;
25use PhpOffice\Common\XMLWriter;
26use PhpOffice\PhpPresentation\PhpPresentation;
27use PhpOffice\PhpPresentation\Shape\Chart;
28use PhpOffice\PhpPresentation\Shape\Chart\Gridlines;
29use PhpOffice\PhpPresentation\Shape\Chart\Legend;
30use PhpOffice\PhpPresentation\Shape\Chart\PlotArea;
31use PhpOffice\PhpPresentation\Shape\Chart\Title;
32use PhpOffice\PhpPresentation\Shape\Chart\Type\Area;
33use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar;
34use PhpOffice\PhpPresentation\Shape\Chart\Type\Bar3D;
35use PhpOffice\PhpPresentation\Shape\Chart\Type\Doughnut;
36use PhpOffice\PhpPresentation\Shape\Chart\Type\Line;
37use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie;
38use PhpOffice\PhpPresentation\Shape\Chart\Type\Pie3D;
39use PhpOffice\PhpPresentation\Shape\Chart\Type\Radar;
40use PhpOffice\PhpPresentation\Shape\Chart\Type\Scatter;
41use PhpOffice\PhpPresentation\Style\Border;
42use PhpOffice\PhpPresentation\Style\Fill;
43use PhpOffice\PhpSpreadsheet\Cell\Coordinate;
44use PhpOffice\PhpSpreadsheet\IOFactory;
45use PhpOffice\PhpSpreadsheet\Spreadsheet;
46
47class PptCharts extends AbstractDecoratorWriter
48{
49    /**
50     * @throws \Exception
51     */
52    public function render(): ZipInterface
53    {
54        for ($i = 0; $i < $this->getDrawingHashTable()->count(); ++$i) {
55            $shape = $this->getDrawingHashTable()->getByIndex($i);
56            if ($shape instanceof Chart) {
57                $this->getZip()->addFromString('ppt/charts/' . $shape->getIndexedFilename(), $this->writeChart($shape));
58
59                if ($shape->hasIncludedSpreadsheet()) {
60                    $this->getZip()->addFromString('ppt/charts/_rels/' . $shape->getIndexedFilename() . '.rels', $this->writeChartRelationships($shape));
61                    $pFilename = tempnam(sys_get_temp_dir(), 'PhpSpreadsheet');
62                    $this->getZip()->addFromString('ppt/embeddings/' . $shape->getIndexedFilename() . '.xlsx', $this->writeSpreadsheet($this->getPresentation(), $shape, $pFilename . '.xlsx'));
63
64                    // remove temp file
65                    if (false === @unlink($pFilename)) {
66                        throw new \Exception('The file ' . $pFilename . ' could not removed.');
67                    }
68                }
69            }
70        }
71
72        return $this->getZip();
73    }
74
75    /**
76     * Write chart to XML format.
77     *
78     * @return string XML Output
79     *
80     * @throws \Exception
81     */
82    public function writeChart(Chart $chart): string
83    {
84        // Create XML writer
85        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
86
87        // XML header
88        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
89
90        // c:chartSpace
91        $objWriter->startElement('c:chartSpace');
92        $objWriter->writeAttribute('xmlns:c', 'http://schemas.openxmlformats.org/drawingml/2006/chart');
93        $objWriter->writeAttribute('xmlns:a', 'http://schemas.openxmlformats.org/drawingml/2006/main');
94        $objWriter->writeAttribute('xmlns:r', 'http://schemas.openxmlformats.org/officeDocument/2006/relationships');
95
96        // c:date1904
97        $objWriter->startElement('c:date1904');
98        $objWriter->writeAttribute('val', '1');
99        $objWriter->endElement();
100
101        // c:lang
102        $objWriter->startElement('c:lang');
103        $objWriter->writeAttribute('val', 'en-US');
104        $objWriter->endElement();
105
106        // c:chart
107        $objWriter->startElement('c:chart');
108
109        // Title?
110        if ($chart->getTitle()->isVisible()) {
111            // Write title
112            $this->writeTitle($objWriter, $chart->getTitle());
113        }
114
115        // c:autoTitleDeleted
116        $objWriter->startElement('c:autoTitleDeleted');
117        $objWriter->writeAttribute('val', $chart->getTitle()->isVisible() ? '0' : '1');
118        $objWriter->endElement();
119
120        // c:view3D
121        $objWriter->startElement('c:view3D');
122
123        // c:rotX
124        $objWriter->startElement('c:rotX');
125        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationX());
126        $objWriter->endElement();
127
128        // c:hPercent
129        $hPercent = $chart->getView3D()->getHeightPercent();
130        $objWriter->writeElementIf(null != $hPercent, 'c:hPercent', 'val', $hPercent);
131
132        // c:rotY
133        $objWriter->startElement('c:rotY');
134        $objWriter->writeAttribute('val', $chart->getView3D()->getRotationY());
135        $objWriter->endElement();
136
137        // c:depthPercent
138        $objWriter->startElement('c:depthPercent');
139        $objWriter->writeAttribute('val', $chart->getView3D()->getDepthPercent());
140        $objWriter->endElement();
141
142        // c:rAngAx
143        $objWriter->startElement('c:rAngAx');
144        $objWriter->writeAttribute('val', $chart->getView3D()->hasRightAngleAxes() ? '1' : '0');
145        $objWriter->endElement();
146
147        // c:perspective
148        $objWriter->startElement('c:perspective');
149        $objWriter->writeAttribute('val', $chart->getView3D()->getPerspective());
150        $objWriter->endElement();
151
152        $objWriter->endElement();
153
154        // Write plot area
155        $this->writePlotArea($objWriter, $chart->getPlotArea(), $chart);
156
157        // Legend?
158        if ($chart->getLegend()->isVisible()) {
159            // Write legend
160            $this->writeLegend($objWriter, $chart->getLegend());
161        }
162
163        // c:plotVisOnly
164        $objWriter->startElement('c:plotVisOnly');
165        $objWriter->writeAttribute('val', '1');
166        $objWriter->endElement();
167
168        // c:dispBlanksAs
169        $objWriter->startElement('c:dispBlanksAs');
170        $objWriter->writeAttribute('val', $chart->getDisplayBlankAs());
171        $objWriter->endElement();
172
173        $objWriter->endElement();
174
175        // c:spPr
176        $objWriter->startElement('c:spPr');
177
178        // Fill
179        $this->writeFill($objWriter, $chart->getFill());
180
181        // Border
182        if (Border::LINE_NONE != $chart->getBorder()->getLineStyle()) {
183            $this->writeBorder($objWriter, $chart->getBorder(), '');
184        }
185
186        // Shadow
187        if ($chart->getShadow()->isVisible()) {
188            // a:effectLst
189            $objWriter->startElement('a:effectLst');
190
191            // a:outerShdw
192            $objWriter->startElement('a:outerShdw');
193            $objWriter->writeAttribute('blurRad', CommonDrawing::pixelsToEmu($chart->getShadow()->getBlurRadius()));
194            $objWriter->writeAttribute('dist', CommonDrawing::pixelsToEmu($chart->getShadow()->getDistance()));
195            $objWriter->writeAttribute('dir', CommonDrawing::degreesToAngle((int) $chart->getShadow()->getDirection()));
196            $objWriter->writeAttribute('algn', $chart->getShadow()->getAlignment());
197            $objWriter->writeAttribute('rotWithShape', '0');
198
199            $this->writeColor($objWriter, $chart->getShadow()->getColor(), $chart->getShadow()->getAlpha());
200
201            $objWriter->endElement();
202
203            $objWriter->endElement();
204        }
205
206        $objWriter->endElement();
207
208        // External data?
209        if ($chart->hasIncludedSpreadsheet()) {
210            // c:externalData
211            $objWriter->startElement('c:externalData');
212            $objWriter->writeAttribute('r:id', 'rId1');
213
214            // c:autoUpdate
215            $objWriter->startElement('c:autoUpdate');
216            $objWriter->writeAttribute('val', '0');
217            $objWriter->endElement();
218
219            $objWriter->endElement();
220        }
221
222        $objWriter->endElement();
223
224        // Return
225        return $objWriter->getData();
226    }
227
228    /**
229     * Write chart to XML format.
230     *
231     * @return string String output
232     *
233     * @throws \Exception
234     */
235    public function writeSpreadsheet(PhpPresentation $presentation, Chart $chart, string $tempName): string
236    {
237        // Need output?
238        if (!$chart->hasIncludedSpreadsheet()) {
239            throw new \Exception('No spreadsheet output is required for the given chart.');
240        }
241
242        // Create new spreadsheet
243        $spreadsheet = new Spreadsheet();
244
245        // Set properties
246        $title = $chart->getTitle()->getText();
247        if (0 == strlen($title)) {
248            $title = 'Chart';
249        }
250        $spreadsheet->getProperties()
251            ->setCreator(
252                $presentation->getDocumentProperties()->getCreator())->setLastModifiedBy(
253                    $presentation->getDocumentProperties()->getLastModifiedBy()
254                )
255            ->setTitle($title);
256
257        // Add chart data
258        $sheet = $spreadsheet->setActiveSheetIndex(0);
259        $sheet->setTitle('Sheet1');
260
261        // Write series
262        $seriesIndex = 0;
263        foreach ($chart->getPlotArea()->getType()->getSeries() as $series) {
264            // Title
265            $sheet->setCellValueByColumnAndRow(1 + $seriesIndex, 1, $series->getTitle());
266
267            // X-axis
268            $axisXData = array_keys($series->getValues());
269            $numAxisXData = count($axisXData);
270            for ($i = 0; $i < $numAxisXData; ++$i) {
271                $sheet->setCellValueByColumnAndRow(0, $i + 2, $axisXData[$i]);
272            }
273
274            // Y-axis
275            $axisYData = array_values($series->getValues());
276            $numAxisYData = count($axisYData);
277            for ($i = 0; $i < $numAxisYData; ++$i) {
278                $sheet->setCellValueByColumnAndRow(1 + $seriesIndex, $i + 2, $axisYData[$i]);
279            }
280
281            ++$seriesIndex;
282        }
283
284        // Save to string
285        $writer = IOFactory::createWriter($spreadsheet, 'Xlsx');
286        $writer->save($tempName);
287
288        // Load file in memory
289        $returnValue = file_get_contents($tempName);
290        if (false === @unlink($tempName)) {
291            throw new \Exception('The file ' . $tempName . ' could not removed.');
292        }
293
294        return $returnValue;
295    }
296
297    /**
298     * Write element with value attribute.
299     *
300     * @param XMLWriter $objWriter XML Writer
301     */
302    protected function writeElementWithValAttribute(XMLWriter $objWriter, string $elementName, string $value): void
303    {
304        $objWriter->startElement($elementName);
305        $objWriter->writeAttribute('val', $value);
306        $objWriter->endElement();
307    }
308
309    /**
310     * Write single value or reference.
311     *
312     * @param XMLWriter $objWriter XML Writer
313     */
314    protected function writeSingleValueOrReference(XMLWriter $objWriter, bool $isReference, string $value, string $reference): void
315    {
316        if (!$isReference) {
317            // Value
318            $objWriter->writeElement('c:v', $value);
319
320            return;
321        }
322
323        // Reference and cache
324        // c:strRef
325        $objWriter->startElement('c:strRef');
326        // c:strRef/c:f
327        $objWriter->writeElement('c:f', $reference);
328        // c:strRef/c:strCache
329        $objWriter->startElement('c:strCache');
330        // c:strRef/c:strCache/c:ptCount
331        $objWriter->startElement('c:ptCount');
332        $objWriter->writeAttribute('val', '1');
333        $objWriter->endElement();
334
335        // c:strRef/c:strCache/c:pt
336        $objWriter->startElement('c:pt');
337        $objWriter->writeAttribute('idx', '0');
338        // c:strRef/c:strCache/c:pt/c:v
339        $objWriter->writeElement('c:v', $value);
340        // c:strRef/c:strCache/c:pt
341        $objWriter->endElement();
342        // c:strRef/c:strCache
343        $objWriter->endElement();
344        // c:strRef
345        $objWriter->endElement();
346    }
347
348    /**
349     * Write series value or reference.
350     *
351     * @param XMLWriter $objWriter XML Writer
352     * @param array<int, mixed> $values
353     */
354    protected function writeMultipleValuesOrReference(XMLWriter $objWriter, bool $isReference, array $values, string $reference): void
355    {
356        // c:strLit / c:numLit
357        // c:strRef / c:numRef
358        $referenceType = ($isReference ? 'Ref' : 'Lit');
359        $dataType = is_numeric($values[0]) ? 'num' : 'str';
360        $objWriter->startElement('c:' . $dataType . $referenceType);
361
362        $numValues = count($values);
363        if (!$isReference) {
364            // Value
365
366            // c:ptCount
367            $objWriter->startElement('c:ptCount');
368            $objWriter->writeAttribute('val', count($values));
369            $objWriter->endElement();
370
371            // Add points
372            for ($i = 0; $i < $numValues; ++$i) {
373                // c:pt
374                $objWriter->startElement('c:pt');
375                $objWriter->writeAttribute('idx', $i);
376                $objWriter->writeElement('c:v', $values[$i]);
377                $objWriter->endElement();
378            }
379        } else {
380            // Reference
381            $objWriter->writeElement('c:f', $reference);
382            $objWriter->startElement('c:' . $dataType . 'Cache');
383
384            // c:ptCount
385            $objWriter->startElement('c:ptCount');
386            $objWriter->writeAttribute('val', count($values));
387            $objWriter->endElement();
388
389            // Add points
390            for ($i = 0; $i < $numValues; ++$i) {
391                // c:pt
392                $objWriter->startElement('c:pt');
393                $objWriter->writeAttribute('idx', $i);
394                $objWriter->writeElement('c:v', $values[$i]);
395                $objWriter->endElement();
396            }
397
398            $objWriter->endElement();
399        }
400
401        $objWriter->endElement();
402    }
403
404    /**
405     * Write Title.
406     *
407     * @param XMLWriter $objWriter XML Writer
408     *
409     * @throws \Exception
410     */
411    protected function writeTitle(XMLWriter $objWriter, Title $subject): void
412    {
413        // c:title
414        $objWriter->startElement('c:title');
415
416        // c:tx
417        $objWriter->startElement('c:tx');
418
419        // c:rich
420        $objWriter->startElement('c:rich');
421
422        // a:bodyPr
423        $objWriter->writeElement('a:bodyPr', null);
424
425        // a:lstStyle
426        $objWriter->writeElement('a:lstStyle', null);
427
428        // a:p
429        $objWriter->startElement('a:p');
430
431        // a:pPr
432        $objWriter->startElement('a:pPr');
433        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
434        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
435        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
436        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
437        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
438        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
439
440        // a:defRPr
441        $objWriter->writeElement('a:defRPr', null);
442
443        $objWriter->endElement();
444
445        // a:r
446        $objWriter->startElement('a:r');
447
448        // a:rPr
449        $objWriter->startElement('a:rPr');
450        $objWriter->writeAttribute('lang', 'en-US');
451        $objWriter->writeAttribute('dirty', '0');
452        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
453        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
454        $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
455        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
456        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
457        $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000');
458        $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000');
459
460        // Font - a:solidFill
461        $objWriter->startElement('a:solidFill');
462
463        $this->writeColor($objWriter, $subject->getFont()->getColor());
464
465        $objWriter->endElement();
466
467        // Font - a:latin
468        $objWriter->startElement('a:latin');
469        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
470        $objWriter->endElement();
471
472        $objWriter->endElement();
473
474        // a:t
475        $objWriter->writeElement('a:t', $subject->getText());
476
477        $objWriter->endElement();
478
479        // a:endParaRPr
480        $objWriter->startElement('a:endParaRPr');
481        $objWriter->writeAttribute('lang', 'en-US');
482        $objWriter->writeAttribute('dirty', '0');
483        $objWriter->endElement();
484
485        $objWriter->endElement();
486
487        $objWriter->endElement();
488
489        $objWriter->endElement();
490
491        // Write layout
492        $this->writeLayout($objWriter, $subject);
493
494        // c:overlay
495        $objWriter->startElement('c:overlay');
496        $objWriter->writeAttribute('val', '0');
497        $objWriter->endElement();
498
499        $objWriter->endElement();
500    }
501
502    /**
503     * Write Plot Area.
504     *
505     * @param XMLWriter $objWriter XML Writer
506     *
507     * @throws \Exception
508     */
509    protected function writePlotArea(XMLWriter $objWriter, PlotArea $subject, Chart $chart): void
510    {
511        // c:plotArea
512        $objWriter->startElement('c:plotArea');
513
514        // Write layout
515        $this->writeLayout($objWriter, $subject);
516
517        // Write chart
518        $chartType = $subject->getType();
519        if ($chartType instanceof Area) {
520            $this->writeTypeArea($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
521        } elseif ($chartType instanceof Bar) {
522            $this->writeTypeBar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
523        } elseif ($chartType instanceof Bar3D) {
524            $this->writeTypeBar3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
525        } elseif ($chartType instanceof Doughnut) {
526            $this->writeTypeDoughnut($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
527        } elseif ($chartType instanceof Pie) {
528            $this->writeTypePie($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
529        } elseif ($chartType instanceof Pie3D) {
530            $this->writeTypePie3D($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
531        } elseif ($chartType instanceof Line) {
532            $this->writeTypeLine($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
533        } elseif ($chartType instanceof Radar) {
534            $this->writeTypeRadar($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
535        } elseif ($chartType instanceof Scatter) {
536            $this->writeTypeScatter($objWriter, $chartType, $chart->hasIncludedSpreadsheet());
537        } else {
538            throw new \Exception('The chart type provided could not be rendered.');
539        }
540
541        // Write X axis?
542        if ($chartType->hasAxisX()) {
543            $this->writeAxis($objWriter, $subject->getAxisX(), Chart\Axis::AXIS_X, $chartType);
544        }
545
546        // Write Y axis?
547        if ($chartType->hasAxisY()) {
548            $this->writeAxis($objWriter, $subject->getAxisY(), Chart\Axis::AXIS_Y, $chartType);
549        }
550
551        $objWriter->endElement();
552    }
553
554    /**
555     * Write Legend.
556     *
557     * @param XMLWriter $objWriter XML Writer
558     * @param Chart\Legend $subject
559     *
560     * @throws \Exception
561     */
562    protected function writeLegend(XMLWriter $objWriter, Legend $subject): void
563    {
564        // c:legend
565        $objWriter->startElement('c:legend');
566
567        // c:legendPos
568        $objWriter->startElement('c:legendPos');
569        $objWriter->writeAttribute('val', $subject->getPosition());
570        $objWriter->endElement();
571
572        // Write layout
573        $this->writeLayout($objWriter, $subject);
574
575        // c:overlay
576        $objWriter->startElement('c:overlay');
577        $objWriter->writeAttribute('val', '0');
578        $objWriter->endElement();
579
580        // c:spPr
581        $objWriter->startElement('c:spPr');
582
583        // Fill
584        $this->writeFill($objWriter, $subject->getFill());
585
586        // Border
587        if (Border::LINE_NONE != $subject->getBorder()->getLineStyle()) {
588            $this->writeBorder($objWriter, $subject->getBorder(), '');
589        }
590
591        $objWriter->endElement();
592
593        // c:txPr
594        $objWriter->startElement('c:txPr');
595
596        // a:bodyPr
597        $objWriter->writeElement('a:bodyPr', null);
598
599        // a:lstStyle
600        $objWriter->writeElement('a:lstStyle', null);
601
602        // a:p
603        $objWriter->startElement('a:p');
604
605        // a:pPr
606        $objWriter->startElement('a:pPr');
607        $objWriter->writeAttribute('algn', $subject->getAlignment()->getHorizontal());
608        $objWriter->writeAttribute('fontAlgn', $subject->getAlignment()->getVertical());
609        $objWriter->writeAttribute('marL', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginLeft()));
610        $objWriter->writeAttribute('marR', CommonDrawing::pixelsToEmu($subject->getAlignment()->getMarginRight()));
611        $objWriter->writeAttribute('indent', CommonDrawing::pixelsToEmu($subject->getAlignment()->getIndent()));
612        $objWriter->writeAttribute('lvl', $subject->getAlignment()->getLevel());
613
614        // a:defRPr
615        $objWriter->startElement('a:defRPr');
616
617        $objWriter->writeAttribute('b', ($subject->getFont()->isBold() ? 'true' : 'false'));
618        $objWriter->writeAttribute('i', ($subject->getFont()->isItalic() ? 'true' : 'false'));
619        $objWriter->writeAttribute('strike', ($subject->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
620        $objWriter->writeAttribute('sz', ($subject->getFont()->getSize() * 100));
621        $objWriter->writeAttribute('u', $subject->getFont()->getUnderline());
622        $objWriter->writeAttributeIf($subject->getFont()->isSuperScript(), 'baseline', '300000');
623        $objWriter->writeAttributeIf($subject->getFont()->isSubScript(), 'baseline', '-250000');
624
625        // Font - a:solidFill
626        $objWriter->startElement('a:solidFill');
627
628        $this->writeColor($objWriter, $subject->getFont()->getColor());
629
630        $objWriter->endElement();
631
632        // Font - a:latin
633        $objWriter->startElement('a:latin');
634        $objWriter->writeAttribute('typeface', $subject->getFont()->getName());
635        $objWriter->endElement();
636
637        $objWriter->endElement();
638
639        $objWriter->endElement();
640
641        // a:endParaRPr
642        $objWriter->startElement('a:endParaRPr');
643        $objWriter->writeAttribute('lang', 'en-US');
644        $objWriter->writeAttribute('dirty', '0');
645        $objWriter->endElement();
646
647        $objWriter->endElement();
648
649        $objWriter->endElement();
650
651        $objWriter->endElement();
652    }
653
654    /**
655     * Write Layout.
656     *
657     * @param XMLWriter $objWriter XML Writer
658     * @param Legend|PlotArea|Title $subject
659     *
660     * @throws \Exception
661     */
662    protected function writeLayout(XMLWriter $objWriter, $subject): void
663    {
664        // c:layout
665        $objWriter->startElement('c:layout');
666
667        // c:manualLayout
668        $objWriter->startElement('c:manualLayout');
669        // c:xMode
670        $objWriter->startElement('c:xMode');
671        $objWriter->writeAttribute('val', 'edge');
672        $objWriter->endElement();
673
674        // c:yMode
675        $objWriter->startElement('c:yMode');
676        $objWriter->writeAttribute('val', 'edge');
677        $objWriter->endElement();
678
679        if (0 != $subject->getOffsetX()) {
680            // c:x
681            $objWriter->startElement('c:x');
682            $objWriter->writeAttribute('val', $subject->getOffsetX());
683            $objWriter->endElement();
684        }
685
686        if (0 != $subject->getOffsetY()) {
687            // c:y
688            $objWriter->startElement('c:y');
689            $objWriter->writeAttribute('val', $subject->getOffsetY());
690            $objWriter->endElement();
691        }
692
693        if (0 != $subject->getWidth()) {
694            // c:w
695            $objWriter->startElement('c:w');
696            $objWriter->writeAttribute('val', $subject->getWidth());
697            $objWriter->endElement();
698        }
699
700        if (0 != $subject->getHeight()) {
701            // c:h
702            $objWriter->startElement('c:h');
703            $objWriter->writeAttribute('val', $subject->getHeight());
704            $objWriter->endElement();
705        }
706
707        $objWriter->endElement();
708        $objWriter->endElement();
709    }
710
711    /**
712     * Write Type Area.
713     *
714     * @param XMLWriter $objWriter XML Writer
715     * @param Chart\Type\Area $subject
716     *
717     * @throws \Exception
718     */
719    protected function writeTypeArea(XMLWriter $objWriter, Area $subject, bool $includeSheet = false): void
720    {
721        // c:lineChart
722        $objWriter->startElement('c:areaChart');
723
724        // c:grouping
725        $objWriter->startElement('c:grouping');
726        $objWriter->writeAttribute('val', 'standard');
727        $objWriter->endElement();
728
729        // Write series
730        $seriesIndex = 0;
731        foreach ($subject->getSeries() as $series) {
732            // c:ser
733            $objWriter->startElement('c:ser');
734
735            // c:ser > c:idx
736            $objWriter->startElement('c:idx');
737            $objWriter->writeAttribute('val', $seriesIndex);
738            $objWriter->endElement();
739
740            // c:ser > c:order
741            $objWriter->startElement('c:order');
742            $objWriter->writeAttribute('val', $seriesIndex);
743            $objWriter->endElement();
744
745            // c:ser > c:tx
746            $objWriter->startElement('c:tx');
747            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
748            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
749            $objWriter->endElement();
750
751            // c:ser > c:dLbls
752            // @link : https://msdn.microsoft.com/en-us/library/documentformat.openxml.drawing.charts.areachartseries.aspx
753            $objWriter->startElement('c:dLbls');
754
755            // c:ser > c:dLbls > c:showVal
756            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
757
758            // c:ser > c:dLbls > c:showCatName
759            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
760
761            // c:ser > c:dLbls > c:showSerName
762            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
763
764            // c:ser > c:dLbls > c:showPercent
765            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
766
767            // c:ser > ##c:dLbls
768            $objWriter->endElement();
769
770            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
771                // c:spPr
772                $objWriter->startElement('c:spPr');
773                // Write fill
774                $this->writeFill($objWriter, $series->getFill());
775                // ## c:spPr
776                $objWriter->endElement();
777            }
778
779            // Write X axis data
780            $axisXData = array_keys($series->getValues());
781
782            // c:cat
783            $objWriter->startElement('c:cat');
784            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
785            $objWriter->endElement();
786
787            // Write Y axis data
788            $axisYData = array_values($series->getValues());
789
790            // c:val
791            $objWriter->startElement('c:val');
792            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
793            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
794            $objWriter->endElement();
795
796            $objWriter->endElement();
797
798            ++$seriesIndex;
799        }
800
801        // c:axId
802        $objWriter->startElement('c:axId');
803        $objWriter->writeAttribute('val', '52743552');
804        $objWriter->endElement();
805
806        // c:axId
807        $objWriter->startElement('c:axId');
808        $objWriter->writeAttribute('val', '52749440');
809        $objWriter->endElement();
810
811        $objWriter->endElement();
812    }
813
814    /**
815     * Write Type Bar.
816     *
817     * @param XMLWriter $objWriter XML Writer
818     * @param Chart\Type\Bar $subject
819     *
820     * @throws \Exception
821     */
822    protected function writeTypeBar(XMLWriter $objWriter, Bar $subject, bool $includeSheet = false): void
823    {
824        // c:barChart
825        $objWriter->startElement('c:barChart');
826
827        // c:barDir
828        $objWriter->startElement('c:barDir');
829        $objWriter->writeAttribute('val', $subject->getBarDirection());
830        $objWriter->endElement();
831
832        // c:grouping
833        $objWriter->startElement('c:grouping');
834        $objWriter->writeAttribute('val', $subject->getBarGrouping());
835        $objWriter->endElement();
836
837        // Write series
838        $seriesIndex = 0;
839        foreach ($subject->getSeries() as $series) {
840            // c:ser
841            $objWriter->startElement('c:ser');
842
843            // c:idx
844            $objWriter->startElement('c:idx');
845            $objWriter->writeAttribute('val', $seriesIndex);
846            $objWriter->endElement();
847
848            // c:order
849            $objWriter->startElement('c:order');
850            $objWriter->writeAttribute('val', $seriesIndex);
851            $objWriter->endElement();
852
853            // c:tx
854            $objWriter->startElement('c:tx');
855            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
856            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
857            $objWriter->endElement();
858
859            // Fills for points?
860            $dataPointFills = $series->getDataPointFills();
861            foreach ($dataPointFills as $key => $value) {
862                // c:dPt
863                $objWriter->startElement('c:dPt');
864
865                // c:idx
866                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
867
868                if (Fill::FILL_NONE != $value->getFillType()) {
869                    // c:spPr
870                    $objWriter->startElement('c:spPr');
871                    // Write fill
872                    $this->writeFill($objWriter, $value);
873                    // ## c:spPr
874                    $objWriter->endElement();
875                }
876
877                // ## c:dPt
878                $objWriter->endElement();
879            }
880
881            // c:dLbls
882            $objWriter->startElement('c:dLbls');
883
884            if ($series->hasDlblNumFormat()) {
885                //c:numFmt
886                $objWriter->startElement('c:numFmt');
887                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
888                $objWriter->writeAttribute('sourceLinked', '0');
889                $objWriter->endElement();
890            }
891
892            // c:txPr
893            $objWriter->startElement('c:txPr');
894
895            // a:bodyPr
896            $objWriter->writeElement('a:bodyPr');
897
898            // a:lstStyle
899            $objWriter->writeElement('a:lstStyle');
900
901            // a:p
902            $objWriter->startElement('a:p');
903
904            // a:pPr
905            $objWriter->startElement('a:pPr');
906
907            // a:defRPr
908            $objWriter->startElement('a:defRPr');
909
910            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
911            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
912            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
913            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
914            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
915            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
916            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
917
918            // a:solidFill
919            $objWriter->startElement('a:solidFill');
920            $this->writeColor($objWriter, $series->getFont()->getColor());
921            // >a:solidFill
922            $objWriter->endElement();
923            // a:latin
924            $objWriter->startElement('a:latin');
925            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
926            // >a:latin
927            $objWriter->endElement();
928
929            // >a:defRPr
930            $objWriter->endElement();
931            // >a:pPr
932            $objWriter->endElement();
933
934            // a:endParaRPr
935            $objWriter->startElement('a:endParaRPr');
936            $objWriter->writeAttribute('lang', 'en-US');
937            $objWriter->writeAttribute('dirty', '0');
938            $objWriter->endElement();
939
940            // >a:p
941            $objWriter->endElement();
942            // >a:lstStyle
943            $objWriter->endElement();
944
945            // c:dLblPos
946            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
947
948            // c:showVal
949            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
950
951            // c:showCatName
952            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
953
954            // c:showSerName
955            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
956
957            // c:showPercent
958            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
959
960            // c:separator
961            $objWriter->writeElement('c:separator', $series->hasShowSeparator() ? $series->getSeparator() : '');
962
963            // c:showLeaderLines
964            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
965
966            $objWriter->endElement();
967
968            // c:spPr
969            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
970                // c:spPr
971                $objWriter->startElement('c:spPr');
972                // Write fill
973                $this->writeFill($objWriter, $series->getFill());
974                // ## c:spPr
975                $objWriter->endElement();
976            }
977
978            // Write X axis data
979            $axisXData = array_keys($series->getValues());
980
981            // c:cat
982            $objWriter->startElement('c:cat');
983            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
984            $objWriter->endElement();
985
986            // Write Y axis data
987            $axisYData = array_values($series->getValues());
988
989            // c:val
990            $objWriter->startElement('c:val');
991            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
992            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
993            $objWriter->endElement();
994
995            $objWriter->endElement();
996
997            ++$seriesIndex;
998        }
999
1000        // c:gapWidth
1001        $objWriter->startElement('c:gapWidth');
1002        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
1003        $objWriter->endElement();
1004
1005        // c:overlap
1006        $objWriter->startElement('c:overlap');
1007        $objWriter->writeAttribute('val', $subject->getOverlapWidthPercent());
1008        $objWriter->endElement();
1009
1010        // c:axId
1011        $objWriter->startElement('c:axId');
1012        $objWriter->writeAttribute('val', '52743552');
1013        $objWriter->endElement();
1014
1015        // c:axId
1016        $objWriter->startElement('c:axId');
1017        $objWriter->writeAttribute('val', '52749440');
1018        $objWriter->endElement();
1019
1020        // c:extLst
1021        $objWriter->startElement('c:extLst');
1022        $objWriter->endElement();
1023
1024        $objWriter->endElement();
1025    }
1026
1027    /**
1028     * Write Type Bar3D.
1029     *
1030     * @param XMLWriter $objWriter XML Writer
1031     * @param Chart\Type\Bar3D $subject
1032     *
1033     * @throws \Exception
1034     */
1035    protected function writeTypeBar3D(XMLWriter $objWriter, Bar3D $subject, bool $includeSheet = false): void
1036    {
1037        // c:bar3DChart
1038        $objWriter->startElement('c:bar3DChart');
1039
1040        // c:barDir
1041        $objWriter->startElement('c:barDir');
1042        $objWriter->writeAttribute('val', $subject->getBarDirection());
1043        $objWriter->endElement();
1044
1045        // c:grouping
1046        $objWriter->startElement('c:grouping');
1047        $objWriter->writeAttribute('val', $subject->getBarGrouping());
1048        $objWriter->endElement();
1049
1050        // Write series
1051        $seriesIndex = 0;
1052        foreach ($subject->getSeries() as $series) {
1053            // c:ser
1054            $objWriter->startElement('c:ser');
1055
1056            // c:idx
1057            $objWriter->startElement('c:idx');
1058            $objWriter->writeAttribute('val', $seriesIndex);
1059            $objWriter->endElement();
1060
1061            // c:order
1062            $objWriter->startElement('c:order');
1063            $objWriter->writeAttribute('val', $seriesIndex);
1064            $objWriter->endElement();
1065
1066            // c:tx
1067            $objWriter->startElement('c:tx');
1068            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1069            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1070            $objWriter->endElement();
1071
1072            // Fills for points?
1073            $dataPointFills = $series->getDataPointFills();
1074            foreach ($dataPointFills as $key => $value) {
1075                // c:dPt
1076                $objWriter->startElement('c:dPt');
1077
1078                // c:idx
1079                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1080
1081                if (Fill::FILL_NONE != $value->getFillType()) {
1082                    // c:spPr
1083                    $objWriter->startElement('c:spPr');
1084                    // Write fill
1085                    $this->writeFill($objWriter, $value);
1086                    // ## c:spPr
1087                    $objWriter->endElement();
1088                }
1089
1090                // ## c:dPt
1091                $objWriter->endElement();
1092            }
1093
1094            // c:dLbls
1095            $objWriter->startElement('c:dLbls');
1096
1097            // c:txPr
1098            $objWriter->startElement('c:txPr');
1099
1100            // a:bodyPr
1101            $objWriter->writeElement('a:bodyPr', null);
1102
1103            // a:lstStyle
1104            $objWriter->writeElement('a:lstStyle', null);
1105
1106            // a:p
1107            $objWriter->startElement('a:p');
1108
1109            // a:pPr
1110            $objWriter->startElement('a:pPr');
1111
1112            // a:defRPr
1113            $objWriter->startElement('a:defRPr');
1114
1115            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1116            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1117            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1118            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1119            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1120            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1121            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1122
1123            // Font - a:solidFill
1124            $objWriter->startElement('a:solidFill');
1125
1126            $this->writeColor($objWriter, $series->getFont()->getColor());
1127
1128            $objWriter->endElement();
1129
1130            // Font - a:latin
1131            $objWriter->startElement('a:latin');
1132            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1133            $objWriter->endElement();
1134
1135            $objWriter->endElement();
1136
1137            $objWriter->endElement();
1138
1139            // a:endParaRPr
1140            $objWriter->startElement('a:endParaRPr');
1141            $objWriter->writeAttribute('lang', 'en-US');
1142            $objWriter->writeAttribute('dirty', '0');
1143            $objWriter->endElement();
1144
1145            $objWriter->endElement();
1146
1147            $objWriter->endElement();
1148
1149            // c:showVal
1150            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1151
1152            // c:showCatName
1153            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1154
1155            // c:showSerName
1156            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1157
1158            // c:showPercent
1159            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1160
1161            // c:showLeaderLines
1162            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1163
1164            $objWriter->endElement();
1165
1166            // c:spPr
1167            if (Fill::FILL_NONE != $series->getFill()->getFillType()) {
1168                // c:spPr
1169                $objWriter->startElement('c:spPr');
1170                // Write fill
1171                $this->writeFill($objWriter, $series->getFill());
1172                // ## c:spPr
1173                $objWriter->endElement();
1174            }
1175
1176            // Write X axis data
1177            $axisXData = array_keys($series->getValues());
1178
1179            // c:cat
1180            $objWriter->startElement('c:cat');
1181            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1182            $objWriter->endElement();
1183
1184            // Write Y axis data
1185            $axisYData = array_values($series->getValues());
1186
1187            // c:val
1188            $objWriter->startElement('c:val');
1189            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1190            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1191            $objWriter->endElement();
1192
1193            $objWriter->endElement();
1194
1195            ++$seriesIndex;
1196        }
1197
1198        // c:gapWidth
1199        $objWriter->startElement('c:gapWidth');
1200        $objWriter->writeAttribute('val', $subject->getGapWidthPercent());
1201        $objWriter->endElement();
1202
1203        // c:axId
1204        $objWriter->startElement('c:axId');
1205        $objWriter->writeAttribute('val', '52743552');
1206        $objWriter->endElement();
1207
1208        // c:axId
1209        $objWriter->startElement('c:axId');
1210        $objWriter->writeAttribute('val', '52749440');
1211        $objWriter->endElement();
1212
1213        // c:axId
1214        $objWriter->startElement('c:axId');
1215        $objWriter->writeAttribute('val', '0');
1216        $objWriter->endElement();
1217
1218        $objWriter->endElement();
1219    }
1220
1221    /**
1222     * Write Type Pie.
1223     *
1224     * @param XMLWriter $objWriter XML Writer
1225     *
1226     * @throws \Exception
1227     */
1228    protected function writeTypeDoughnut(XMLWriter $objWriter, Doughnut $subject, bool $includeSheet = false): void
1229    {
1230        // c:pieChart
1231        $objWriter->startElement('c:doughnutChart');
1232
1233        // c:varyColors
1234        $objWriter->startElement('c:varyColors');
1235        $objWriter->writeAttribute('val', '1');
1236        $objWriter->endElement();
1237
1238        // Write series
1239        $seriesIndex = 0;
1240        foreach ($subject->getSeries() as $series) {
1241            // c:ser
1242            $objWriter->startElement('c:ser');
1243
1244            // c:idx
1245            $objWriter->startElement('c:idx');
1246            $objWriter->writeAttribute('val', $seriesIndex);
1247            $objWriter->endElement();
1248
1249            // c:order
1250            $objWriter->startElement('c:order');
1251            $objWriter->writeAttribute('val', $seriesIndex);
1252            $objWriter->endElement();
1253
1254            // c:tx
1255            $objWriter->startElement('c:tx');
1256            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1257            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1258            $objWriter->endElement();
1259
1260            // Fills for points?
1261            $dataPointFills = $series->getDataPointFills();
1262            foreach ($dataPointFills as $key => $value) {
1263                // c:dPt
1264                $objWriter->startElement('c:dPt');
1265                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1266                // c:dPt/c:spPr
1267                $objWriter->startElement('c:spPr');
1268                $this->writeFill($objWriter, $value);
1269                // c:dPt/##c:spPr
1270                $objWriter->endElement();
1271                // ##c:dPt
1272                $objWriter->endElement();
1273            }
1274
1275            // Write X axis data
1276            $axisXData = array_keys($series->getValues());
1277
1278            // c:cat
1279            $objWriter->startElement('c:cat');
1280            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1281            $objWriter->endElement();
1282
1283            // Write Y axis data
1284            $axisYData = array_values($series->getValues());
1285
1286            // c:val
1287            $objWriter->startElement('c:val');
1288            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1289            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1290            $objWriter->endElement();
1291
1292            $objWriter->endElement();
1293
1294            ++$seriesIndex;
1295        }
1296
1297        if (isset($series) && is_object($series) && $series instanceof Chart\Series) {
1298            // c:dLbls
1299            $objWriter->startElement('c:dLbls');
1300
1301            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1302            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1303            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1304            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1305            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1306            $this->writeElementWithValAttribute($objWriter, 'c:showBubbleSize', '0');
1307            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1308
1309            if ($series->hasDlblNumFormat()) {
1310                //c:numFmt
1311                $objWriter->startElement('c:numFmt');
1312                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1313                $objWriter->writeAttribute('sourceLinked', '0');
1314                $objWriter->endElement();
1315            }
1316
1317            // c:dLbls\c:txPr
1318            $objWriter->startElement('c:txPr');
1319            $objWriter->writeElement('a:bodyPr', null);
1320            $objWriter->writeElement('a:lstStyle', null);
1321
1322            // c:dLbls\c:txPr\a:p
1323            $objWriter->startElement('a:p');
1324
1325            // c:dLbls\c:txPr\a:p\a:pPr
1326            $objWriter->startElement('a:pPr');
1327
1328            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr
1329            $objWriter->startElement('a:defRPr');
1330            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1331            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1332            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1333            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1334            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1335            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1336            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1337
1338            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:solidFill
1339            $objWriter->startElement('a:solidFill');
1340            $this->writeColor($objWriter, $series->getFont()->getColor());
1341            $objWriter->endElement();
1342
1343            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\a:latin
1344            $objWriter->startElement('a:latin');
1345            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1346            $objWriter->endElement();
1347
1348            // c:dLbls\c:txPr\a:p\a:pPr\a:defRPr\
1349            $objWriter->endElement();
1350            // c:dLbls\c:txPr\a:p\a:pPr\
1351            $objWriter->endElement();
1352
1353            // c:dLbls\c:txPr\a:p\a:endParaRPr
1354            $objWriter->startElement('a:endParaRPr');
1355            $objWriter->writeAttribute('lang', 'en-US');
1356            $objWriter->writeAttribute('dirty', '0');
1357            $objWriter->endElement();
1358
1359            // c:dLbls\c:txPr\a:p\
1360            $objWriter->endElement();
1361            // c:dLbls\c:txPr\
1362            $objWriter->endElement();
1363
1364            $separator = $series->getSeparator();
1365            if (!empty($separator) && PHP_EOL != $separator) {
1366                // c:dLbls\c:separator
1367                $objWriter->writeElement('c:separator', $separator);
1368            }
1369
1370            // c:dLbls\
1371            $objWriter->endElement();
1372        }
1373
1374        $this->writeElementWithValAttribute($objWriter, 'c:firstSliceAng', '0');
1375        $this->writeElementWithValAttribute($objWriter, 'c:holeSize', (string) $subject->getHoleSize());
1376
1377        $objWriter->endElement();
1378    }
1379
1380    /**
1381     * Write Type Pie.
1382     *
1383     * @param XMLWriter $objWriter XML Writer
1384     *
1385     * @throws \Exception
1386     */
1387    protected function writeTypePie(XMLWriter $objWriter, Pie $subject, bool $includeSheet = false): void
1388    {
1389        // c:pieChart
1390        $objWriter->startElement('c:pieChart');
1391
1392        // c:varyColors
1393        $objWriter->startElement('c:varyColors');
1394        $objWriter->writeAttribute('val', '1');
1395        $objWriter->endElement();
1396
1397        // Write series
1398        $seriesIndex = 0;
1399        foreach ($subject->getSeries() as $series) {
1400            // c:ser
1401            $objWriter->startElement('c:ser');
1402
1403            // c:idx
1404            $objWriter->startElement('c:idx');
1405            $objWriter->writeAttribute('val', $seriesIndex);
1406            $objWriter->endElement();
1407
1408            // c:order
1409            $objWriter->startElement('c:order');
1410            $objWriter->writeAttribute('val', $seriesIndex);
1411            $objWriter->endElement();
1412
1413            // c:tx
1414            $objWriter->startElement('c:tx');
1415            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1416            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1417            $objWriter->endElement();
1418
1419            // Fills for points?
1420            $dataPointFills = $series->getDataPointFills();
1421            foreach ($dataPointFills as $key => $value) {
1422                // c:dPt
1423                $objWriter->startElement('c:dPt');
1424                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1425                // c:dPt/c:spPr
1426                $objWriter->startElement('c:spPr');
1427                $this->writeFill($objWriter, $value);
1428                // c:dPt/##c:spPr
1429                $objWriter->endElement();
1430                // ##c:dPt
1431                $objWriter->endElement();
1432            }
1433
1434            // c:dLbls
1435            $objWriter->startElement('c:dLbls');
1436
1437            if ($series->hasDlblNumFormat()) {
1438                //c:numFmt
1439                $objWriter->startElement('c:numFmt');
1440                $objWriter->writeAttribute('formatCode', $series->getDlblNumFormat());
1441                $objWriter->writeAttribute('sourceLinked', '0');
1442                $objWriter->endElement();
1443            }
1444
1445            // c:txPr
1446            $objWriter->startElement('c:txPr');
1447
1448            // a:bodyPr
1449            $objWriter->writeElement('a:bodyPr', null);
1450
1451            // a:lstStyle
1452            $objWriter->writeElement('a:lstStyle', null);
1453
1454            // a:p
1455            $objWriter->startElement('a:p');
1456
1457            // a:pPr
1458            $objWriter->startElement('a:pPr');
1459
1460            // a:defRPr
1461            $objWriter->startElement('a:defRPr');
1462
1463            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1464            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1465            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1466            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1467            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1468            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1469            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1470
1471            // Font - a:solidFill
1472            $objWriter->startElement('a:solidFill');
1473
1474            $this->writeColor($objWriter, $series->getFont()->getColor());
1475
1476            $objWriter->endElement();
1477
1478            // Font - a:latin
1479            $objWriter->startElement('a:latin');
1480            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1481            $objWriter->endElement();
1482
1483            $objWriter->endElement();
1484
1485            $objWriter->endElement();
1486
1487            // a:endParaRPr
1488            $objWriter->startElement('a:endParaRPr');
1489            $objWriter->writeAttribute('lang', 'en-US');
1490            $objWriter->writeAttribute('dirty', '0');
1491            $objWriter->endElement();
1492
1493            $objWriter->endElement();
1494
1495            $objWriter->endElement();
1496
1497            // c:dLblPos
1498            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1499
1500            // c:showLegendKey
1501            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1502
1503            // c:showVal
1504            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1505
1506            // c:showCatName
1507            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1508
1509            // c:showSerName
1510            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1511
1512            // c:showPercent
1513            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1514
1515            // c:showLeaderLines
1516            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1517
1518            $objWriter->endElement();
1519
1520            // Write X axis data
1521            $axisXData = array_keys($series->getValues());
1522
1523            // c:cat
1524            $objWriter->startElement('c:cat');
1525            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1526            $objWriter->endElement();
1527
1528            // Write Y axis data
1529            $axisYData = array_values($series->getValues());
1530
1531            // c:val
1532            $objWriter->startElement('c:val');
1533            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1534            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1535            $objWriter->endElement();
1536
1537            $objWriter->endElement();
1538
1539            ++$seriesIndex;
1540        }
1541
1542        $objWriter->endElement();
1543    }
1544
1545    /**
1546     * Write Type Pie3D.
1547     *
1548     * @param XMLWriter $objWriter XML Writer
1549     *
1550     * @throws \Exception
1551     */
1552    protected function writeTypePie3D(XMLWriter $objWriter, Pie3D $subject, bool $includeSheet = false): void
1553    {
1554        // c:pie3DChart
1555        $objWriter->startElement('c:pie3DChart');
1556
1557        // c:varyColors
1558        $objWriter->startElement('c:varyColors');
1559        $objWriter->writeAttribute('val', '1');
1560        $objWriter->endElement();
1561
1562        // Write series
1563        $seriesIndex = 0;
1564        foreach ($subject->getSeries() as $series) {
1565            // c:ser
1566            $objWriter->startElement('c:ser');
1567
1568            // c:idx
1569            $objWriter->startElement('c:idx');
1570            $objWriter->writeAttribute('val', $seriesIndex);
1571            $objWriter->endElement();
1572
1573            // c:order
1574            $objWriter->startElement('c:order');
1575            $objWriter->writeAttribute('val', $seriesIndex);
1576            $objWriter->endElement();
1577
1578            // c:tx
1579            $objWriter->startElement('c:tx');
1580            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1581            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1582            $objWriter->endElement();
1583
1584            // c:explosion
1585            $objWriter->startElement('c:explosion');
1586            $objWriter->writeAttribute('val', $subject->getExplosion());
1587            $objWriter->endElement();
1588
1589            // Fills for points?
1590            $dataPointFills = $series->getDataPointFills();
1591            foreach ($dataPointFills as $key => $value) {
1592                // c:dPt
1593                $objWriter->startElement('c:dPt');
1594                $this->writeElementWithValAttribute($objWriter, 'c:idx', (string) $key);
1595                // c:dPt/c:spPr
1596                $objWriter->startElement('c:spPr');
1597                $this->writeFill($objWriter, $value);
1598                // c:dPt/##c:spPr
1599                $objWriter->endElement();
1600                // ##c:dPt
1601                $objWriter->endElement();
1602            }
1603
1604            // c:dLbls
1605            $objWriter->startElement('c:dLbls');
1606
1607            // c:txPr
1608            $objWriter->startElement('c:txPr');
1609
1610            // a:bodyPr
1611            $objWriter->writeElement('a:bodyPr', null);
1612
1613            // a:lstStyle
1614            $objWriter->writeElement('a:lstStyle', null);
1615
1616            // a:p
1617            $objWriter->startElement('a:p');
1618
1619            // a:pPr
1620            $objWriter->startElement('a:pPr');
1621
1622            // a:defRPr
1623            $objWriter->startElement('a:defRPr');
1624
1625            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1626            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1627            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1628            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1629            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1630            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1631            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1632
1633            // Font - a:solidFill
1634            $objWriter->startElement('a:solidFill');
1635
1636            $this->writeColor($objWriter, $series->getFont()->getColor());
1637
1638            $objWriter->endElement();
1639
1640            // Font - a:latin
1641            $objWriter->startElement('a:latin');
1642            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1643            $objWriter->endElement();
1644
1645            $objWriter->endElement();
1646
1647            $objWriter->endElement();
1648
1649            // a:endParaRPr
1650            $objWriter->startElement('a:endParaRPr');
1651            $objWriter->writeAttribute('lang', 'en-US');
1652            $objWriter->writeAttribute('dirty', '0');
1653            $objWriter->endElement();
1654
1655            $objWriter->endElement();
1656
1657            $objWriter->endElement();
1658
1659            // c:dLblPos
1660            $this->writeElementWithValAttribute($objWriter, 'c:dLblPos', $series->getLabelPosition());
1661
1662            // c:showVal
1663            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1664
1665            // c:showCatName
1666            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1667
1668            // c:showSerName
1669            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1670
1671            // c:showPercent
1672            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1673
1674            // c:showLeaderLines
1675            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1676
1677            $objWriter->endElement();
1678
1679            // Write X axis data
1680            $axisXData = array_keys($series->getValues());
1681
1682            // c:cat
1683            $objWriter->startElement('c:cat');
1684            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1685            $objWriter->endElement();
1686
1687            // Write Y axis data
1688            $axisYData = array_values($series->getValues());
1689
1690            // c:val
1691            $objWriter->startElement('c:val');
1692            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1693            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1694            $objWriter->endElement();
1695
1696            $objWriter->endElement();
1697
1698            ++$seriesIndex;
1699        }
1700
1701        $objWriter->endElement();
1702    }
1703
1704    /**
1705     * Write Type Line.
1706     *
1707     * @param XMLWriter $objWriter XML Writer
1708     *
1709     * @throws \Exception
1710     */
1711    protected function writeTypeLine(XMLWriter $objWriter, Line $subject, bool $includeSheet = false): void
1712    {
1713        // c:lineChart
1714        $objWriter->startElement('c:lineChart');
1715
1716        // c:grouping
1717        $objWriter->startElement('c:grouping');
1718        $objWriter->writeAttribute('val', 'standard');
1719        $objWriter->endElement();
1720
1721        // Write series
1722        $seriesIndex = 0;
1723        foreach ($subject->getSeries() as $series) {
1724            // c:ser
1725            $objWriter->startElement('c:ser');
1726
1727            // c:idx
1728            $objWriter->startElement('c:idx');
1729            $objWriter->writeAttribute('val', $seriesIndex);
1730            $objWriter->endElement();
1731
1732            // c:order
1733            $objWriter->startElement('c:order');
1734            $objWriter->writeAttribute('val', $seriesIndex);
1735            $objWriter->endElement();
1736
1737            // c:tx
1738            $objWriter->startElement('c:tx');
1739            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1740            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1741            $objWriter->endElement();
1742
1743            // c:spPr
1744            $objWriter->startElement('c:spPr');
1745            // Write fill
1746            $this->writeFill($objWriter, $series->getFill());
1747            // Write outline
1748            $this->writeOutline($objWriter, $series->getOutline());
1749            // ## c:spPr
1750            $objWriter->endElement();
1751
1752            // Marker
1753            $this->writeSeriesMarker($objWriter, $series->getMarker());
1754
1755            // c:dLbls
1756            $objWriter->startElement('c:dLbls');
1757
1758            // c:txPr
1759            $objWriter->startElement('c:txPr');
1760
1761            // a:bodyPr
1762            $objWriter->writeElement('a:bodyPr', null);
1763
1764            // a:lstStyle
1765            $objWriter->writeElement('a:lstStyle', null);
1766
1767            // a:p
1768            $objWriter->startElement('a:p');
1769
1770            // a:pPr
1771            $objWriter->startElement('a:pPr');
1772
1773            // a:defRPr
1774            $objWriter->startElement('a:defRPr');
1775
1776            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1777            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1778            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1779            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1780            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1781            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
1782            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
1783
1784            // Font - a:solidFill
1785            $objWriter->startElement('a:solidFill');
1786
1787            $this->writeColor($objWriter, $series->getFont()->getColor());
1788
1789            $objWriter->endElement();
1790
1791            // Font - a:latin
1792            $objWriter->startElement('a:latin');
1793            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1794            $objWriter->endElement();
1795
1796            $objWriter->endElement();
1797
1798            $objWriter->endElement();
1799
1800            // a:endParaRPr
1801            $objWriter->startElement('a:endParaRPr');
1802            $objWriter->writeAttribute('lang', 'en-US');
1803            $objWriter->writeAttribute('dirty', '0');
1804            $objWriter->endElement();
1805
1806            $objWriter->endElement();
1807
1808            $objWriter->endElement();
1809
1810            // c:showVal
1811            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1812
1813            // c:showCatName
1814            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1815
1816            // c:showSerName
1817            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1818
1819            // c:showPercent
1820            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1821
1822            // c:showLeaderLines
1823            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1824
1825            // > c:dLbls
1826            $objWriter->endElement();
1827
1828            // Write X axis data
1829            $axisXData = array_keys($series->getValues());
1830
1831            // c:cat
1832            $objWriter->startElement('c:cat');
1833            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
1834            $objWriter->endElement();
1835
1836            // Write Y axis data
1837            $axisYData = array_values($series->getValues());
1838
1839            // c:val
1840            $objWriter->startElement('c:val');
1841            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
1842            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
1843            $objWriter->endElement();
1844
1845            // c:smooth
1846            $objWriter->startElement('c:smooth');
1847            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
1848            $objWriter->endElement();
1849
1850            $objWriter->endElement();
1851
1852            ++$seriesIndex;
1853        }
1854
1855        // c:marker
1856        $objWriter->startElement('c:marker');
1857        $objWriter->writeAttribute('val', '1');
1858        $objWriter->endElement();
1859
1860        // c:axId
1861        $objWriter->startElement('c:axId');
1862        $objWriter->writeAttribute('val', '52743552');
1863        $objWriter->endElement();
1864
1865        // c:axId
1866        $objWriter->startElement('c:axId');
1867        $objWriter->writeAttribute('val', '52749440');
1868        $objWriter->endElement();
1869
1870        $objWriter->endElement();
1871    }
1872
1873    /**
1874     * Write Type Radar
1875     *
1876     * @param XMLWriter $objWriter XML Writer
1877     * @param Radar $subject
1878     * @param bool $includeSheet
1879     *
1880     * @throws \Exception
1881     */
1882    protected function writeTypeRadar(XMLWriter $objWriter, Radar $subject, bool $includeSheet = false): void
1883    {
1884        // c:scatterChart
1885        $objWriter->startElement('c:radarChart');
1886
1887        // c:radarStyle
1888        $objWriter->startElement('c:radarStyle');
1889        $objWriter->writeAttribute('val', 'marker');
1890        $objWriter->endElement();
1891
1892        // c:varyColors
1893        $objWriter->startElement('c:varyColors');
1894        $objWriter->writeAttribute('val', '0');
1895        $objWriter->endElement();
1896
1897        // Write series
1898        $seriesIndex = 0;
1899        foreach ($subject->getSeries() as $series) {
1900            // c:ser
1901            $objWriter->startElement('c:ser');
1902
1903            // c:idx
1904            $objWriter->startElement('c:idx');
1905            $objWriter->writeAttribute('val', $seriesIndex);
1906            $objWriter->endElement();
1907
1908            // c:order
1909            $objWriter->startElement('c:order');
1910            $objWriter->writeAttribute('val', $seriesIndex);
1911            $objWriter->endElement();
1912
1913            // c:tx
1914            $objWriter->startElement('c:tx');
1915            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
1916            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
1917            $objWriter->endElement();
1918
1919            // Marker
1920            $this->writeSeriesMarker($objWriter, $series->getMarker());
1921
1922            // c:dLbls
1923            $objWriter->startElement('c:dLbls');
1924
1925            // c:txPr
1926            $objWriter->startElement('c:txPr');
1927
1928            // a:bodyPr
1929            $objWriter->writeElement('a:bodyPr', null);
1930
1931            // a:lstStyle
1932            $objWriter->writeElement('a:lstStyle', null);
1933
1934            // a:p
1935            $objWriter->startElement('a:p');
1936
1937            // a:pPr
1938            $objWriter->startElement('a:pPr');
1939
1940            // a:defRPr
1941            $objWriter->startElement('a:defRPr');
1942
1943            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
1944            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
1945            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
1946            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
1947            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
1948            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '30000');
1949            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-25000');
1950
1951            // Font - a:solidFill
1952            $objWriter->startElement('a:solidFill');
1953
1954            $this->writeColor($objWriter, $series->getFont()->getColor());
1955
1956            $objWriter->endElement();
1957
1958            // Font - a:latin
1959            $objWriter->startElement('a:latin');
1960            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
1961            $objWriter->endElement();
1962
1963            $objWriter->endElement();
1964
1965            $objWriter->endElement();
1966
1967            // a:endParaRPr
1968            $objWriter->startElement('a:endParaRPr');
1969            $objWriter->writeAttribute('lang', 'en-US');
1970            $objWriter->writeAttribute('dirty', '0');
1971            $objWriter->endElement();
1972
1973            $objWriter->endElement();
1974
1975            $objWriter->endElement();
1976
1977            // c:showLegendKey
1978            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
1979
1980            // c:showVal
1981            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
1982
1983            // c:showCatName
1984            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
1985
1986            // c:showSerName
1987            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
1988
1989            // c:showPercent
1990            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
1991
1992            // c:showLeaderLines
1993            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
1994
1995            $objWriter->endElement();
1996
1997            // c:spPr
1998            $objWriter->startElement('c:spPr');
1999            // Write fill
2000            $this->writeFill($objWriter, $series->getFill());
2001            // Write outline
2002            $this->writeOutline($objWriter, $series->getOutline());
2003            // ## c:spPr
2004            $objWriter->endElement();
2005
2006            // Write X axis data
2007            $axisXData = array_keys($series->getValues());
2008
2009            // c:cat
2010            $objWriter->startElement('c:cat');
2011            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
2012            $objWriter->endElement();
2013
2014            // Write Y axis data
2015            $axisYData = array_values($series->getValues());
2016
2017            // c:val
2018            $objWriter->startElement('c:val');
2019            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
2020            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2021            $objWriter->endElement();
2022
2023            // c:smooth
2024            $objWriter->startElement('c:smooth');
2025            $objWriter->writeAttribute('val', '0');
2026            $objWriter->endElement();
2027
2028            $objWriter->endElement();
2029
2030            ++$seriesIndex;
2031        }
2032
2033        // c:axId
2034        $objWriter->startElement('c:axId');
2035        $objWriter->writeAttribute('val', '52743552');
2036        $objWriter->endElement();
2037
2038        // c:axId
2039        $objWriter->startElement('c:axId');
2040        $objWriter->writeAttribute('val', '52749440');
2041        $objWriter->endElement();
2042
2043        $objWriter->endElement();
2044    }
2045
2046    /**
2047     * Write Type Scatter
2048     *
2049     * @throws \Exception
2050     */
2051    protected function writeTypeScatter(XMLWriter $objWriter, Scatter $subject, bool $includeSheet = false): void
2052    {
2053        // c:scatterChart
2054        $objWriter->startElement('c:scatterChart');
2055
2056        // c:scatterStyle
2057        $objWriter->startElement('c:scatterStyle');
2058        $objWriter->writeAttribute('val', 'lineMarker');
2059        $objWriter->endElement();
2060
2061        // c:varyColors
2062        $objWriter->startElement('c:varyColors');
2063        $objWriter->writeAttribute('val', '0');
2064        $objWriter->endElement();
2065
2066        // Write series
2067        $seriesIndex = 0;
2068        foreach ($subject->getSeries() as $series) {
2069            // c:ser
2070            $objWriter->startElement('c:ser');
2071
2072            // c:idx
2073            $objWriter->startElement('c:idx');
2074            $objWriter->writeAttribute('val', $seriesIndex);
2075            $objWriter->endElement();
2076
2077            // c:order
2078            $objWriter->startElement('c:order');
2079            $objWriter->writeAttribute('val', $seriesIndex);
2080            $objWriter->endElement();
2081
2082            // c:tx
2083            $objWriter->startElement('c:tx');
2084            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex(1 + $seriesIndex) . '$1' : '');
2085            $this->writeSingleValueOrReference($objWriter, $includeSheet, $series->getTitle(), $coords);
2086            $objWriter->endElement();
2087
2088            // c:spPr
2089            $objWriter->startElement('c:spPr');
2090            // Write fill
2091            $this->writeFill($objWriter, $series->getFill());
2092            // Write outline
2093            $this->writeOutline($objWriter, $series->getOutline());
2094            // ## c:spPr
2095            $objWriter->endElement();
2096
2097            // Marker
2098            $this->writeSeriesMarker($objWriter, $series->getMarker());
2099
2100            // c:dLbls
2101            $objWriter->startElement('c:dLbls');
2102
2103            // c:txPr
2104            $objWriter->startElement('c:txPr');
2105
2106            // a:bodyPr
2107            $objWriter->writeElement('a:bodyPr', null);
2108
2109            // a:lstStyle
2110            $objWriter->writeElement('a:lstStyle', null);
2111
2112            // a:p
2113            $objWriter->startElement('a:p');
2114
2115            // a:pPr
2116            $objWriter->startElement('a:pPr');
2117
2118            // a:defRPr
2119            $objWriter->startElement('a:defRPr');
2120
2121            $objWriter->writeAttribute('b', ($series->getFont()->isBold() ? 'true' : 'false'));
2122            $objWriter->writeAttribute('i', ($series->getFont()->isItalic() ? 'true' : 'false'));
2123            $objWriter->writeAttribute('strike', ($series->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2124            $objWriter->writeAttribute('sz', ($series->getFont()->getSize() * 100));
2125            $objWriter->writeAttribute('u', $series->getFont()->getUnderline());
2126            $objWriter->writeAttributeIf($series->getFont()->isSuperScript(), 'baseline', '300000');
2127            $objWriter->writeAttributeIf($series->getFont()->isSubScript(), 'baseline', '-250000');
2128
2129            // Font - a:solidFill
2130            $objWriter->startElement('a:solidFill');
2131
2132            $this->writeColor($objWriter, $series->getFont()->getColor());
2133
2134            $objWriter->endElement();
2135
2136            // Font - a:latin
2137            $objWriter->startElement('a:latin');
2138            $objWriter->writeAttribute('typeface', $series->getFont()->getName());
2139            $objWriter->endElement();
2140
2141            $objWriter->endElement();
2142
2143            $objWriter->endElement();
2144
2145            // a:endParaRPr
2146            $objWriter->startElement('a:endParaRPr');
2147            $objWriter->writeAttribute('lang', 'en-US');
2148            $objWriter->writeAttribute('dirty', '0');
2149            $objWriter->endElement();
2150
2151            $objWriter->endElement();
2152
2153            $objWriter->endElement();
2154
2155            // c:showLegendKey
2156            $this->writeElementWithValAttribute($objWriter, 'c:showLegendKey', $series->hasShowLegendKey() ? '1' : '0');
2157
2158            // c:showVal
2159            $this->writeElementWithValAttribute($objWriter, 'c:showVal', $series->hasShowValue() ? '1' : '0');
2160
2161            // c:showCatName
2162            $this->writeElementWithValAttribute($objWriter, 'c:showCatName', $series->hasShowCategoryName() ? '1' : '0');
2163
2164            // c:showSerName
2165            $this->writeElementWithValAttribute($objWriter, 'c:showSerName', $series->hasShowSeriesName() ? '1' : '0');
2166
2167            // c:showPercent
2168            $this->writeElementWithValAttribute($objWriter, 'c:showPercent', $series->hasShowPercentage() ? '1' : '0');
2169
2170            // c:separator
2171            $separator = $series->getSeparator();
2172            if (!empty($separator) && PHP_EOL != $separator) {
2173                // c:dLbls\c:separator
2174                $objWriter->writeElement('c:separator', $separator);
2175            }
2176
2177            // c:showLeaderLines
2178            $this->writeElementWithValAttribute($objWriter, 'c:showLeaderLines', $series->hasShowLeaderLines() ? '1' : '0');
2179
2180            $objWriter->endElement();
2181
2182            // Write X axis data
2183            $axisXData = array_keys($series->getValues());
2184
2185            // c:xVal
2186            $objWriter->startElement('c:xVal');
2187            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisXData, 'Sheet1!$A$2:$A$' . (1 + count($axisXData)));
2188            $objWriter->endElement();
2189
2190            // Write Y axis data
2191            $axisYData = array_values($series->getValues());
2192
2193            // c:yVal
2194            $objWriter->startElement('c:yVal');
2195            $coords = ($includeSheet ? 'Sheet1!$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$2:$' . Coordinate::stringFromColumnIndex($seriesIndex + 1) . '$' . (1 + count($axisYData)) : '');
2196            $this->writeMultipleValuesOrReference($objWriter, $includeSheet, $axisYData, $coords);
2197            $objWriter->endElement();
2198
2199            // c:smooth
2200            $objWriter->startElement('c:smooth');
2201            $objWriter->writeAttribute('val', $subject->isSmooth() ? '1' : '0');
2202            $objWriter->endElement();
2203
2204            $objWriter->endElement();
2205
2206            ++$seriesIndex;
2207        }
2208
2209        // c:axId
2210        $objWriter->startElement('c:axId');
2211        $objWriter->writeAttribute('val', '52743552');
2212        $objWriter->endElement();
2213
2214        // c:axId
2215        $objWriter->startElement('c:axId');
2216        $objWriter->writeAttribute('val', '52749440');
2217        $objWriter->endElement();
2218
2219        $objWriter->endElement();
2220    }
2221
2222    /**
2223     * Write chart relationships to XML format.
2224     *
2225     * @return string XML Output
2226     *
2227     * @throws \Exception
2228     */
2229    public function writeChartRelationships(Chart $pChart): string
2230    {
2231        // Create XML writer
2232        $objWriter = new XMLWriter(XMLWriter::STORAGE_MEMORY);
2233
2234        // XML header
2235        $objWriter->startDocument('1.0', 'UTF-8', 'yes');
2236
2237        // Relationships
2238        $objWriter->startElement('Relationships');
2239        $objWriter->writeAttribute('xmlns', 'http://schemas.openxmlformats.org/package/2006/relationships');
2240
2241        // Write spreadsheet relationship?
2242        if ($pChart->hasIncludedSpreadsheet()) {
2243            $this->writeRelationship($objWriter, 1, 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/package', '../embeddings/' . $pChart->getIndexedFilename() . '.xlsx');
2244        }
2245
2246        $objWriter->endElement();
2247
2248        // Return
2249        return $objWriter->getData();
2250    }
2251
2252    protected function writeSeriesMarker(XMLWriter $objWriter, Chart\Marker $marker): void
2253    {
2254        // c:marker
2255        $objWriter->startElement('c:marker');
2256        // c:marker > c:symbol
2257        $objWriter->startElement('c:symbol');
2258        $objWriter->writeAttribute('val', $marker->getSymbol());
2259        $objWriter->endElement();
2260
2261        // Size if different of none
2262        if (Chart\Marker::SYMBOL_NONE != $marker->getSymbol()) {
2263            $markerSize = (int) $marker->getSize();
2264            if ($markerSize < 2) {
2265                $markerSize = 2;
2266            }
2267            if ($markerSize > 72) {
2268                $markerSize = 72;
2269            }
2270
2271            /*
2272             * c:marker > c:size
2273             * Size in points
2274             * @link : https://msdn.microsoft.com/en-us/library/hh658135(v=office.12).aspx
2275             */
2276            $objWriter->startElement('c:size');
2277            $objWriter->writeAttribute('val', $markerSize);
2278            $objWriter->endElement();
2279        }
2280
2281        // // c:marker > c:spPr
2282        $objWriter->startElement('c:spPr');
2283        $this->writeFill($objWriter, $marker->getFill());
2284        $this->writeBorder($objWriter, $marker->getBorder(), '', true);
2285        $objWriter->endElement();
2286
2287        // > c:marker
2288        $objWriter->endElement();
2289    }
2290
2291    /**
2292     * @throws \Exception
2293     */
2294    protected function writeAxis(XMLWriter $objWriter, Chart\Axis $oAxis, string $typeAxis, Chart\Type\AbstractType $typeChart): void
2295    {
2296        if (Chart\Axis::AXIS_X != $typeAxis && Chart\Axis::AXIS_Y != $typeAxis) {
2297            return;
2298        }
2299
2300        if (Chart\Axis::AXIS_X == $typeAxis) {
2301            $mainElement = 'c:catAx';
2302            $axIdVal = '52743552';
2303            $axPosVal = 'b';
2304            $crossAxVal = '52749440';
2305        } else {
2306            $mainElement = 'c:valAx';
2307            $axIdVal = '52749440';
2308            $axPosVal = 'l';
2309            $crossAxVal = '52743552';
2310        }
2311
2312        // $mainElement
2313        $objWriter->startElement($mainElement);
2314
2315        // $mainElement > c:axId
2316        $objWriter->startElement('c:axId');
2317        $objWriter->writeAttribute('val', $axIdVal);
2318        $objWriter->endElement();
2319
2320        // $mainElement > c:scaling
2321        $objWriter->startElement('c:scaling');
2322
2323        // $mainElement > c:scaling > c:orientation
2324        $objWriter->startElement('c:orientation');
2325        $objWriter->writeAttribute('val', 'minMax');
2326        $objWriter->endElement();
2327
2328        if (null != $oAxis->getMaxBounds()) {
2329            $objWriter->startElement('c:max');
2330            $objWriter->writeAttribute('val', $oAxis->getMaxBounds());
2331            $objWriter->endElement();
2332        }
2333
2334        if (null != $oAxis->getMinBounds()) {
2335            $objWriter->startElement('c:min');
2336            $objWriter->writeAttribute('val', $oAxis->getMinBounds());
2337            $objWriter->endElement();
2338        }
2339
2340        // $mainElement > ##c:scaling
2341        $objWriter->endElement();
2342
2343        // $mainElement > c:delete
2344        $objWriter->startElement('c:delete');
2345        $objWriter->writeAttribute('val', $oAxis->isVisible() ? '0' : '1');
2346        $objWriter->endElement();
2347
2348        // $mainElement > c:axPos
2349        $objWriter->startElement('c:axPos');
2350        $objWriter->writeAttribute('val', $axPosVal);
2351        $objWriter->endElement();
2352
2353        $oMajorGridlines = $oAxis->getMajorGridlines();
2354        if ($oMajorGridlines instanceof Gridlines) {
2355            $objWriter->startElement('c:majorGridlines');
2356
2357            $this->writeAxisGridlines($objWriter, $oMajorGridlines);
2358
2359            $objWriter->endElement();
2360        }
2361
2362        $oMinorGridlines = $oAxis->getMinorGridlines();
2363        if ($oMinorGridlines instanceof Gridlines) {
2364            $objWriter->startElement('c:minorGridlines');
2365
2366            $this->writeAxisGridlines($objWriter, $oMinorGridlines);
2367
2368            $objWriter->endElement();
2369        }
2370
2371        if ('' != $oAxis->getTitle()) {
2372            // c:title
2373            $objWriter->startElement('c:title');
2374
2375            // c:tx
2376            $objWriter->startElement('c:tx');
2377
2378            // c:rich
2379            $objWriter->startElement('c:rich');
2380
2381            // a:bodyPr
2382            $objWriter->startElement('a:bodyPr');
2383            $objWriter->writeAttributeIf($oAxis->getTitleRotation() != 0, 'rot', CommonDrawing::degreesToAngle((int) $oAxis->getTitleRotation()));
2384            $objWriter->endElement();
2385
2386            // a:lstStyle
2387            $objWriter->writeElement('a:lstStyle', null);
2388
2389            // a:p
2390            $objWriter->startElement('a:p');
2391
2392            // a:pPr
2393            $objWriter->startElement('a:pPr');
2394
2395            // a:defRPr
2396            $objWriter->startElement('a:defRPr');
2397
2398            $objWriter->writeAttribute('b', ($oAxis->getFont()->isBold() ? 'true' : 'false'));
2399            $objWriter->writeAttribute('i', ($oAxis->getFont()->isItalic() ? 'true' : 'false'));
2400            $objWriter->writeAttribute('strike', ($oAxis->getFont()->isStrikethrough() ? 'sngStrike' : 'noStrike'));
2401            $objWriter->writeAttribute('sz', ($oAxis->getFont()->getSize() * 100));
2402            $objWriter->writeAttribute('u', $oAxis->getFont()->getUnderline());
2403            $objWriter->writeAttributeIf($oAxis->getFont()->isSuperScript(), 'baseline', '300000');
2404            $objWriter->writeAttributeIf($oAxis->getFont()->isSubScript(), 'baseline', '-250000');
2405
2406            // Font - a:solidFill
2407            $objWriter->startElement('a:solidFill');
2408            $this->writeColor($objWriter, $oAxis->getFont()->getColor());
2409            $objWriter->endElement();
2410
2411            // Font - a:latin
2412            $objWriter->startElement('a:latin');
2413            $objWriter->writeAttribute('typeface', $oAxis->getFont()->getName());
2414            $objWriter->endElement();
2415
2416            $objWriter->endElement();
2417
2418            // ## a:pPr
2419            $objWriter->endElement();
2420
2421            // a:r
2422            $objWriter->startElement('a:r');
2423
2424            // a:rPr
2425            $objWriter->startElement('a:rPr');
2426            $objWriter->writeAttribute('lang', 'en-US');
2427            $objWriter->writeAttribute('dirty', '0');
2428            $objWriter->endElement();
2429
2430            // a:t
2431            $objWriter->writeElement('a:t', $oAxis->getTitle());
2432
2433            // ## a:r
2434            $objWriter->endElement();
2435
2436            // a:endParaRPr
2437            $objWriter->startElement('a:endParaRPr');
2438            $objWriter->writeAttribute('lang', 'en-US');
2439            $objWriter->writeAttribute('dirty', '0');
2440            $objWriter->endElement();
2441
2442            // ## a:p
2443            $objWriter->endElement();
2444
2445            // ## c:rich
2446            $objWriter->endElement();
2447
2448            // ## c:tx
2449            $objWriter->endElement();
2450
2451            // ## c:title
2452            $objWriter->endElement();
2453        }
2454
2455        // c:numFmt
2456        $objWriter->startElement('c:numFmt');
2457        $objWriter->writeAttribute('formatCode', $oAxis->getFormatCode());
2458        $objWriter->writeAttribute('sourceLinked', '1');
2459        $objWriter->endElement();
2460
2461        // c:majorTickMark
2462        $objWriter->startElement('c:majorTickMark');
2463        $objWriter->writeAttribute('val', $oAxis->getMajorTickMark());
2464        $objWriter->endElement();
2465
2466        // c:minorTickMark
2467        $objWriter->startElement('c:minorTickMark');
2468        $objWriter->writeAttribute('val', $oAxis->getMinorTickMark());
2469        $objWriter->endElement();
2470
2471        // c:tickLblPos
2472        $objWriter->startElement('c:tickLblPos');
2473        $objWriter->writeAttribute('val', $oAxis->getTickLabelPosition());
2474        $objWriter->endElement();
2475
2476        // c:spPr
2477        $objWriter->startElement('c:spPr');
2478        // Outline
2479        $this->writeOutline($objWriter, $oAxis->getOutline());
2480        // ##c:spPr
2481        $objWriter->endElement();
2482
2483        // c:crossAx
2484        $objWriter->startElement('c:crossAx');
2485        $objWriter->writeAttribute('val', $crossAxVal);
2486        $objWriter->endElement();
2487
2488        // c:crosses
2489        $objWriter->startElement('c:crosses');
2490        $objWriter->writeAttribute('val', 'autoZero');
2491        $objWriter->endElement();
2492
2493        if (Chart\Axis::AXIS_X == $typeAxis) {
2494            // c:lblAlgn
2495            $objWriter->startElement('c:lblAlgn');
2496            $objWriter->writeAttribute('val', 'ctr');
2497            $objWriter->endElement();
2498
2499            // c:lblOffset
2500            $objWriter->startElement('c:lblOffset');
2501            $objWriter->writeAttribute('val', '100');
2502            $objWriter->endElement();
2503
2504            // c:majorUnit
2505            if ($oAxis->getMajorUnit() != null) {
2506                $objWriter->startElement('c:tickLblSkip');
2507                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2508                $objWriter->endElement();
2509            }
2510        }
2511
2512        if (Chart\Axis::AXIS_Y == $typeAxis) {
2513            // c:crossBetween
2514            $objWriter->startElement('c:crossBetween');
2515            // midCat : Position Axis On Tick Marks
2516            // between : Between Tick Marks
2517            if ($typeChart instanceof Area) {
2518                $objWriter->writeAttribute('val', 'midCat');
2519            } else {
2520                $objWriter->writeAttribute('val', 'between');
2521            }
2522            $objWriter->endElement();
2523
2524            // c:majorUnit
2525            if (null != $oAxis->getMajorUnit()) {
2526                $objWriter->startElement('c:majorUnit');
2527                $objWriter->writeAttribute('val', $oAxis->getMajorUnit());
2528                $objWriter->endElement();
2529            }
2530
2531            // c:minorUnit
2532            if (null != $oAxis->getMinorUnit()) {
2533                $objWriter->startElement('c:minorUnit');
2534                $objWriter->writeAttribute('val', $oAxis->getMinorUnit());
2535                $objWriter->endElement();
2536            }
2537        }
2538
2539        $objWriter->endElement();
2540    }
2541
2542    /**
2543     * @throws \Exception
2544     */
2545    protected function writeAxisGridlines(XMLWriter $objWriter, Gridlines $oGridlines): void
2546    {
2547        // c:spPr
2548        $objWriter->startElement('c:spPr');
2549
2550        // Outline
2551        $this->writeOutline($objWriter, $oGridlines->getOutline());
2552
2553        // ##c:spPr
2554        $objWriter->endElement();
2555    }
2556}